/*
 * This file is part of Cadmium.
 * Copyright (C) 2007-2010 Xavier Clerc.
 *
 * Cadmium is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Cadmium is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package fr.x9c.cadmium.support;

import java.awt.BorderLayout;

import fr.x9c.cadmium.kernel.Block;
import fr.x9c.cadmium.kernel.Context;
import fr.x9c.cadmium.kernel.Value;
import fr.x9c.cadmium.primitives.graph.GraphSlot;

/**
 * This class implements an applet based upon the OCaml <i>Graphics</i>
 * library. The applet UI is reduced to a single canvas whose content is
 * controlled by the <i>Graphics</i> library. <br/>
 *
 * @author <a href="mailto:cadmium@x9c.fr">Xavier Clerc</a>
 * @version 1.0
 * @since 1.0
 */
public abstract class Applet extends java.applet.Applet implements Runnable {

    /** Thread executing <i>run</i> closure. */
    private Thread thread;

    /**
     * Empty constructor.
     */
    Applet() {
        super();
    } // end empty constructor

    /**
     * Returns the info associated with the applet, as the value of the
     * callback named <i>"Cadmium.applet.information"</i>.
     * @return the info associated with the applet,
     *         <tt>null</tt> if none
     */
    @Override
    public final String getAppletInfo() {
        final Value cb = getCallback("Cadmium.applet.information");
        return cb != null
            ? cb.asBlock().asString()
            : null;
    } // end method 'getAppletInfo()'

    /**
     * Returns the parameter info associated with the applet, as the value of
     * the callback named <i>"Cadmium.applet.parameters"</i>.
     * @return the parameter info associated with the applet,
     *         <tt>null</tt> if none
     */
    @Override
    public final String[][] getParameterInfo() {
        final Value cb = getCallback("Cadmium.applet.parameters");
        if (cb != null) {
            final Block bl = cb.asBlock();
            final int len = bl.sizeValues();
            final String[][] res = new String[len][3];
            for (int i = 0; i < len; i++) {
                final Block b = bl.get(i).asBlock();
                for (int j = 0; j < 3; j++) {
                    res[i][j] = b.get(j).asBlock().asString();
                } // end for
            } // end for
            return res;
        } else {
            return null;
        } // end if/else
    } // end method 'getParameterInfo()'

    /**
     * Constructs the applet UI, as a bare Canvas whose content is managed
     * by the <i>Graphics</i> library (this method "opens" the library). <br/>
     * Then runs the callback named <i>"Cadmium.applet.init"</i>
     * with <i>this</i> as parameter. <br/>
     * Shows error message in status if an exception is thrown.
     */
    @Override
    public final void init() {
        final Context ctxt = getContext();
        final String geometry =
            getParameter("width") + "x" + getParameter("height");
        final GraphSlot slot = new GraphSlot(ctxt.getParameters(),
                                             "applet",
                                             geometry);
        setLayout(new BorderLayout());
        add(slot.getCanvas(), BorderLayout.CENTER);
        ctxt.registerSlot(GraphSlot.SLOT, slot);
        callback("Cadmium.applet.init");
    } // end method 'init()'

    /**
     * Runs the callback named <i>"Cadmium.applet.start"</i>
     * with <i>this</i> as parameter. <br/>
     * Shows error message in status if an exception is thrown. <br/>
     * Then starts the thread associated with this applet.
     */
    @Override
    public final void start() {
        callback("Cadmium.applet.start");
        this.thread = new Thread(this);
        this.thread.start();
    } // end method 'start()'

    /**
     * Runs the callback named <i>"Cadmium.applet.stop"</i>
     * with <i>this</i> as parameter. <br/>
     * Kills the thread launched by {@link #start()}. <br/>
     * Shows error message in status if an exception is thrown.
     */
    @Override
    @SuppressWarnings("deprecation")
    public final void stop() {
        callback("Cadmium.applet.stop");
        if (this.thread != null) {
            this.thread.stop();
        } // end if
    } // end method 'stop()'

    /**
     * Runs the callback named <i>"Cadmium.applet.destroy"</i>
     * with <i>this</i> as parameter. <br/>
     * Shows error message in status if an exception is thrown.
     */
    @Override
    public final void destroy() {
        callback("Cadmium.applet.destroy");
    } // end method 'destroy()'

    /**
     * Runs the callback named <i>"Cadmium.applet.run"</i>
     * with <i>this</i> as parameter. <br/>
     * Shows error message in status if an exception is thrown.
     */
    public final void run() {
        callback("Cadmium.applet.run");
    } // end method 'run()'

    /**
     * Runs a callback, with <i>this</i> as parameter. <br/>
     * Shows error message in status if an exception is thrown.
     * @param cb callback to run - should not be <tt>null</tt>
     */
    protected abstract void callback(final String cb);

    /**
     * Returns the value of a given callback.
     * @param cb callback to get calue for - should not be <tt>null</tt>
     * @return callback registered with passed name
     */
    protected abstract Value getCallback(final String cb);

    /**
     * Returns the context.
     * @return the context
     */
    protected abstract Context getContext();

} // end class 'Applet'
